package com.sunricher.telinkblemeshlib.models;

import android.annotation.SuppressLint;

import androidx.annotation.Nullable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;

import com.sunricher.telinkblemeshlib.db.UartDaliDeviceManager;

import java.util.HashMap;

@Entity(primaryKeys = {"dali_address", "gateway_address"})
public class UartDaliDevice {

    public static final String DEVICE_TYPE_DT6 = "DT6";
    public static final String DEVICE_TYPE_DT8_CCT = "DT8 CCT";
    public static final String DEVICE_TYPE_DT8_XY = "DT8 XY";
    public static final String DEVICE_TYPE_DT8_RGBW = "DT8 RGBW";
    public static final String DEVICE_TYPE_DT8_RGBWA = "DT8 RGBWA";

    public static HashMap<String, Object> getDefaultDataPoints(String deviceType) {
        HashMap<String, Object> result = new HashMap<>();
        result.put("ON_OFF", true);
        result.put("BRIGHTNESS", 254);
        switch (deviceType) {
            case DEVICE_TYPE_DT6:
                break;
            case DEVICE_TYPE_DT8_CCT:
                result.put("COLOR_TEMPERATURE", 4500);
                break;
            case DEVICE_TYPE_DT8_XY:
                result.put("X", 0);
                result.put("Y", 1);
                break;
            case DEVICE_TYPE_DT8_RGBW:
                result.put("RED", 254);
                result.put("GREEN", 254);
                result.put("BLUE", 254);
                result.put("WHITE", 254);
                break;
            case DEVICE_TYPE_DT8_RGBWA:
                result.put("RED", 254);
                result.put("GREEN", 254);
                result.put("BLUE", 254);
                result.put("WHITE", 254);
                result.put("AMBER", 254);
                break;
            default:
                break;
        }
        return result;
    }

    @ColumnInfo(name = "dali_address")
    private int daliAddress;
    @ColumnInfo(name = "gateway_address")
    private int gatewayAddress;
    @ColumnInfo(name = "device_type")
    private String deviceType;
    @Ignore
    private HashMap<String, Object> dataPoints;
    @Ignore
    private boolean isOnline = true;
    @ColumnInfo(name = "name")
    private String name = "";

    public String getCommonName() {
        return deviceType + " " + daliAddress;
    }

    public UartDaliDevice(int daliAddress, int gatewayAddress, String deviceType) {
        super();
        this.daliAddress = daliAddress;
        this.gatewayAddress = gatewayAddress;
        this.deviceType = deviceType;
        this.dataPoints = UartDaliDevice.getDefaultDataPoints(deviceType);
    }

    @Override
    public boolean equals(@Nullable Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || obj.getClass() != this.getClass()) {
            return false;
        }
        UartDaliDevice newDevice = (UartDaliDevice) obj;
        return this.daliAddress == newDevice.daliAddress && this.gatewayAddress == newDevice.gatewayAddress;
    }

    public int getDaliAddress() {
        return daliAddress;
    }

    public void setDaliAddress(int daliAddress) {
        this.daliAddress = daliAddress;
    }

    public int getGatewayAddress() {
        return gatewayAddress;
    }

    public void setGatewayAddress(int gatewayAddress) {
        this.gatewayAddress = gatewayAddress;
    }

    public String getDeviceType() {
        return deviceType;
    }

    public void setDeviceType(String deviceType) {
        this.deviceType = deviceType;
    }

    public HashMap<String, Object> getDataPoints() {
        return dataPoints;
    }

    public void setDataPoints(HashMap<String, Object> dataPoints) {
        this.dataPoints = dataPoints;
    }

    public boolean isOnline() {
        return isOnline;
    }

    public void setOnline(boolean online) {
        isOnline = online;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // Value Range
    // Level equals brightness

    public static class ValueRange {
        private int minValue;
        private int maxValue;

        public ValueRange(int minValue, int maxValue) {
            this.minValue = minValue;
            this.maxValue = maxValue;
        }

        public int getMinValue() {
            return minValue;
        }

        public void setMinValue(int minValue) {
            this.minValue = minValue;
        }

        public int getMaxValue() {
            return maxValue;
        }

        public void setMaxValue(int maxValue) {
            this.maxValue = maxValue;
        }

        public boolean contains(int value) {
            return value >= minValue && value <= maxValue;
        }
    }

    public static ValueRange levelRange = new ValueRange(1, 254);
    public static ValueRange cctRange = new ValueRange(1000, 10000);

    public static ValueRange stateLevelRange = new ValueRange(0, 254);
    public static int stateLevelMask = 0xFF;

    public static ValueRange stateXyRange = new ValueRange(1, 65534);
    public static int stateXyMask = 0xFFFF;

    public static ValueRange stateCctRange = new ValueRange(1000, 10000);
    public static int stateCctMask = 0xFFFF;

    public static ValueRange stateRgbwafRange = new ValueRange(0, 254);
    public static int stateRgbwafMask = 0xFF;

    public static ValueRange fadeTimeRange = new ValueRange(0, 15);
    public static ValueRange fadeRateRange = new ValueRange(1, 15);

    @SuppressLint("DefaultLocale")
    public static String getConfigLevelRangeDetail(int minLevel, int maxLevel) {
        int minValue = minLevel;
        int maxValue = maxLevel;
        if (!levelRange.contains(minLevel)) {
            minValue = levelRange.getMinValue();
        }
        if (!levelRange.contains(maxLevel)) {
            maxValue = levelRange.getMaxValue();
        }
        float minFloat = (float) minValue * 100.0f / (float) levelRange.getMaxValue();
        float maxFloat = (float) maxValue * 100.0f / (float) levelRange.getMaxValue();
        return String.format("%.1f%%-%.1f%%", minFloat, maxFloat);
    }

    @SuppressLint("DefaultLocale")
    public static String getConfigCctRangeDetail(int minCct, int maxCct) {
        return String.format("%dK-%dK", minCct, maxCct);
    }

    @SuppressLint("DefaultLocale")
    public static String getConfigStateDetail(int level) {
        if (level == 0xFF) {
            return "MASK";
        }
        float valueFloat = (float) level * 100.0f / 254.0f;
        return String.format("%.1f%%", valueFloat);
    }

    private final static String[] fadeTimeValues = new String[]{
            "Extended fade",
            "0.7",
            "1.0",
            "1.4",
            "2.0",
            "2.8",
            "4.0",
            "5.7",
            "8.0",
            "11.3",
            "16.0",
            "22.6",
            "32.0",
            "45.3",
            "64.0",
            "90.5"
    };

    public static String getConfigFadeTimeDetail(int fadeTime, String unit) {
        if (fadeTime == 0) {
            return fadeTimeValues[0];
        }
        if (fadeTime >= 0 && fadeTime < fadeTimeValues.length) {
            return fadeTimeValues[fadeTime] + unit;
        }
        return "";
    }

    private final static String[] fadeRateValues = new String[]{
            "",
            "358",
            "253",
            "179",
            "127",
            "89.4",
            "63.3",
            "44.7",
            "31.6",
            "22.4",
            "15.8",
            "11.2",
            "7.9",
            "5.6",
            "4.0",
            "2.8"
    };

    public static String getConfigFadeRateDetail(int fadeRate, String unit) {
        if (fadeRate > 0 && fadeRate < fadeRateValues.length) {
            return fadeRateValues[fadeRate] + " " + unit;
        }
        return "";
    }
}
